home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / zines / Phrack / Phrack Issue 52.sit / Phrack52 / 52 / P52-10 < prev    next >
Text File  |  1998-01-26  |  17KB  |  566 lines

  1. ---[  Phrack Magazine   Volume 8, Issue 52 January 26, 1998, article 10 of 20
  2.  
  3.  
  4. -------------------------[  a Quick nT Interrogation Probe (QTIP)
  5.  
  6.  
  7. --------[  twitch <twitch@aye.net>
  8.  
  9.  
  10. ----[  INTRODUCTION
  11.  
  12.  
  13.     As you probably already know, certain LanMan derivatives (most notably
  14. Windows NT) sport a stupid feature known as `null sessions`.  Null sessions
  15. allow server connections to be established without the hassle and rigmarole of
  16. username or password authentication.  This is reportedly to ease
  17. administrative tasks (UserManager and ilk utilize them).  Also, such silliness
  18. such as the RedButton bug have shown (although in poor form) that an 
  19. interested/malicious third party can gleen quite a bit of info from `Press any
  20. key to return to index`.  Once established, these connections default to having
  21. permissions to display enumerated user and share lists, get information about 
  22. particular users, wander the registry, etc.  QTIP takes advantage of this,
  23. allowing the user to procure far too much information about the target
  24. machine.  It employs no black magic or hidden technique to do this.  QTIP
  25. works via straight API calls.
  26.  
  27.     As of service pack 3 for NT 4.0, it is possible for the `informed` system
  28. administrator to block null sessions through the registry, effectively
  29. nullifying any threat from QTIP.  I do not, however, believe that there is
  30. such a patch for 3.5.1 machines.  Also, it has not been tested against SAMBA
  31. servers, and as far as the author knows, SAMBA does not support something as
  32. asinine as null sessions (anyone who knows any differently is invited to mail
  33. corrections to the author, or directly to Phrack Magazine).
  34.  
  35.     To prevent these sorts of shenanigans from happening remotely across the
  36. Internet, the concerned system administrator can block NBT traffic at the
  37. gateway (this sort of traffic should not be allowed to/from the Internet as
  38. standard fare).  If you are running NT 4.0, install the service packs, and set
  39. the appropriate registry values to disable the attack.  Or use OpenBSD.
  40.  
  41.  
  42. ----[  THE CODE
  43.  
  44.  
  45.     QTIP has a few options.  qtip -h supplies the following info:
  46.  
  47. usage qtip[asug<username>hv] <target>
  48.         -s:             get share list
  49.         -u:             get user list
  50.         -g <username>:  get infos about <username>
  51.         -d:             leave connection established on exit
  52.         -a:             -s + -u
  53.         -h, -?:         display this help
  54.         -v:             be verbose (use twice to be garrulous)
  55.  
  56.     Seems rather self explanatory.  If the verbose flag is set, then -u
  57. implies a recursive -g.  -d is handy if you plan to take a look at the
  58. registry as well (there's gold in them thar hills).  Omission of all flags just
  59. establishes a null session and exits.  <target> can be a fully-qualified
  60. domain name, ip address, or UNC format.  The code compiles like a dream under
  61. visual c 4.1.  There is no makefile included, just link the code against 
  62. kernel32.lib, libc.lib and wsock32.lib.  This program is most useful wrapped 
  63. in scripts with something like tping(ip sweeper), and maybe a few registry
  64. inquisition perl scripts.  Feel free to redistribute, just give props where
  65. props are due, and please let me know if you make any interesting changes.
  66.  
  67. <++> qtip/qtip.h
  68. /*
  69.  * qtip.h
  70.  * 12/04/1997
  71.  * twitch
  72.  * twitch@aye.net
  73.  *
  74.  * a quick nt investigative probe. (mis)uses null sessions to collect
  75.  * sundry information about a WindowsNT server.  distribute as you
  76.  * please.  be alert, look alive, and act like you kow.
  77.  *
  78.  * '...i should dismiss him, in order to teach him that pleasure consists
  79.  *     not in what i enjoy, but in having my own way.'
  80.  *       -sk, either/or
  81.  */
  82.  
  83. #include <stdio.h>
  84. #include <windows.h>
  85. #include <winsock.h>
  86. #include "lm.h"
  87.  
  88. #define k16             16384
  89. #define TARG_LEN        255
  90. #define USER_LEN        22
  91.  
  92. void handle_error(DWORD);
  93. void prepend_str(char *, char*);
  94. int  open_session();
  95. int  procure_userlist();
  96. int  procure_sharelist();
  97. void parse_cl(int, char **);
  98. void usage(char *);
  99. int powerup(int, char **);
  100. void bail(const char *);
  101. int  close_session();
  102. void get_usr_info(wchar_t *);
  103.  
  104. /* couple o globals to make my life easier */
  105. u_int           OPT_SHARES, OPT_USERS, OPT_GETUI;
  106. u_int           OPT_NODEL,  VERB;
  107. char            target[TARG_LEN];
  108. WCHAR           utarg[TARG_LEN];
  109. WCHAR           user[USER_LEN];
  110. NETRESOURCE     nr;
  111.  
  112. <-->
  113. <++> qtip/qtip.c
  114.  
  115. /*
  116.  * qtip.c
  117.  * 10/04/1997
  118.  * twitch
  119.  * twitch@aye.net
  120.  *
  121.  * a quick nt investigative probe
  122.  * link against kernel32.lib, libc.lib and wsock32.lib.
  123.  * qtip -h for usage.  distribute as you please.
  124.  *
  125.  */
  126.  
  127. #include "qtip.h"
  128.  
  129. int main(int argc, char *argv[])
  130. {
  131.    if( (powerup(argc, argv)) )
  132.       return(1);
  133.  
  134.    if( (open_session()) != 0)
  135.       return(1);
  136.  
  137.    if(OPT_SHARES)
  138.       procure_sharelist();
  139.  
  140.    if(OPT_USERS)
  141.       procure_userlist();
  142.  
  143.    if(OPT_GETUI)
  144.       get_usr_info(utarg);
  145.  
  146.         close_session();
  147.    return(0);
  148. }
  149.  
  150. int open_session()
  151. {
  152.    DWORD                        r;
  153.  
  154.    nr.dwType    = RESOURCETYPE_ANY;
  155.    nr.lpLocalName       = NULL;
  156.    nr.lpProvider        = NULL;
  157.    nr.lpRemoteName = target;
  158.  
  159.    if(VERB)
  160.       printf("establishing null session with %s...\n", target);
  161.  
  162.    r = WNetAddConnection2(&nr, "", "", 0);
  163.    if(r != NO_ERROR){
  164.       handle_error(r);
  165.       return -1;
  166.    }
  167.  
  168.    if(VERB)
  169.      printf("connection established\n");
  170.  
  171.    return 0;
  172. }
  173.  
  174. /*
  175.  * procure_userlist()
  176.  *    just use the old lm NetUserEnum() because there isnt comparable
  177.  *    functionality in the WNet sect.  i just wish the win32 api was
  178.  *    more bloated and obtuse.
  179.  */
  180. int procure_userlist()
  181. {
  182.    NET_API_STATUS               nas;
  183.    LPBYTE                               *buf = NULL;
  184.    DWORD                                        entread, totent, rhand;
  185.    DWORD                                        maxlen = 0xffffffff;
  186.    USER_INFO_0                  *usrs;
  187.    unsigned int    i;
  188.    int                                  cc = 0;
  189.  
  190.    entread = totent = rhand = nas = 0;
  191.    if( (buf = (LPBYTE*)malloc(k16)) == NULL)
  192.                 bail("malloc probs\n");
  193.  
  194.    if(VERB)
  195.      wprintf(L"\ngetting userlist from %s...\n", utarg);
  196.  
  197.    nas = NetUserEnum(utarg, 0, 0, buf, maxlen, &entread, &totent, &rhand);
  198.    if(nas != NERR_Success){
  199.      fprintf(stderr, "couldnt enum users, ");
  200.      handle_error(nas);
  201.      goto cleanup;
  202.    }
  203.  
  204.    cc = sizeof(USER_INFO_0) * entread;
  205.    if( (usrs = (USER_INFO_0 *)malloc(cc)) == NULL){
  206.      fprintf(stderr, "malloc probs\n");
  207.      goto cleanup;
  208.    }
  209.  
  210.    memcpy(usrs, *buf, cc);
  211.    for(i = 0; i < entread; i++){
  212.                 wcscpy(user, usrs[i].usri0_name);
  213.                 wprintf(L"%s\n", user);
  214.                 if(VERB)
  215.                         get_usr_info(utarg);
  216.     }
  217.  
  218. cleanup:
  219.    if(buf)
  220.      free(buf);
  221.  
  222.    return 0;
  223. }
  224.  
  225. /*
  226.  * get_user_info()
  227.  *    attempt to gather some interesting facts about
  228.  *              a user
  229.  */
  230. void get_usr_info(LPWSTR utarg)
  231. {
  232.    NET_API_STATUS nas;
  233.    USER_INFO_1          usrinfos;
  234.    LPBYTE         *buf = NULL;
  235.  
  236.    if( !(buf = (LPBYTE *)malloc(sizeof(USER_INFO_1))) )
  237.      bail("malloc probs\n");
  238.  
  239.    nas = NetUserGetInfo(utarg, user, 1, buf);
  240.  
  241.    if(nas){
  242.      fwprintf(stderr, L"couldnt get user info for for %s, ", user);
  243.      handle_error(nas);
  244.    }
  245.    else{
  246.      memcpy(&usrinfos, *buf, sizeof(USER_INFO_1));
  247.  
  248.      /* most of these will never happen, but nothings lost trying */
  249.      if( (UF_PASSWD_NOTREQD & usrinfos.usri1_flags) )
  250.        printf("\t-password not required, how about that.\n");
  251.      if( (UF_ACCOUNTDISABLE & usrinfos.usri1_flags) )
  252.        printf("\t-account disabled\n");
  253.      if( (UF_LOCKOUT & usrinfos.usri1_flags) )
  254.        printf("\t-account locked out\n");
  255.      if( (UF_DONT_EXPIRE_PASSWD & usrinfos.usri1_flags) )
  256.        printf("\t-password doesnt expire\n");
  257.      if( (UF_PASSWD_CANT_CHANGE & usrinfos.usri1_flags) )
  258.        printf("\t-user cant change password\n");
  259.      if( (UF_WORKSTATION_TRUST_ACCOUNT & usrinfos.usri1_flags) )
  260.        printf("\t-account for some other box in this domain\n");
  261.      if( (UF_SERVER_TRUST_ACCOUNT & usrinfos.usri1_flags) )
  262.        printf("\t-account for what is prolly the BDC\n");
  263.      if( (UF_INTERDOMAIN_TRUST_ACCOUNT & usrinfos.usri1_flags) )
  264.        printf("\t-interdomain permit to trust account\n");
  265.    }
  266.  
  267.    free(buf);
  268. }
  269.  
  270. /*
  271.  * procure_sharelist()
  272.  *    strangely enough, this retrieves a sharelist from target
  273.  */
  274. int procure_sharelist()
  275. {
  276.    DWORD                        r;
  277.    DWORD                        bufsize = 16384, cnt = 0xFFFFFFFF;
  278.    HANDLE               enhan;
  279.    void                 *buf;
  280.    NETRESOURCE  *res;
  281.    u_int                        i;
  282.  
  283.    if( (buf = malloc(bufsize)) == NULL){
  284.       fprintf(stderr, "malloc probs, bailing\n");
  285.       return -1;
  286.    }
  287.  
  288.    nr.dwScope                   = RESOURCE_CONNECTED;
  289.    nr.dwType                    = RESOURCETYPE_ANY;
  290.    nr.dwDisplayType     = 0;
  291.    nr.dwUsage                   = RESOURCEUSAGE_CONTAINER;
  292.    nr.lpLocalName               = NULL;
  293.    nr.lpRemoteName      = (LPTSTR)target;
  294.    nr.lpComment    = NULL;
  295.    nr.lpProvider                = NULL;
  296.  
  297.    r = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
  298.                                                   RESOURCEUSAGE_CONNECTABLE, &nr
  299. , &enhan);
  300.    if(r != 0){
  301.                 free(buf);
  302.                 printf("open_enum failed, sorry- ");
  303.                 handle_error(r);
  304.                 return -1;
  305.    }
  306.  
  307.    r = WNetEnumResource(enhan, &cnt, buf, &bufsize);
  308.    if(r != 0){
  309.       free(buf);
  310.       printf("enum_res failed- ");
  311.                 handle_error(r);
  312.                 return -1;
  313.    }
  314.  
  315.    res = (NETRESOURCE*)malloc(cnt * sizeof(NETRESOURCE));
  316.    if(res == NULL){
  317.       free(buf);
  318.       printf("malloc probs, i wont be listing shares.\n");
  319.                 return -1;
  320.    }
  321.    memcpy(res, buf, (cnt * sizeof(NETRESOURCE)) );
  322.  
  323.    for(i = 0; i < cnt; i++){
  324.       if(VERB)
  325.                         printf("\nshare name:\t");
  326.  
  327.       printf("%s\n", res[i].lpRemoteName);
  328.       if(VERB){
  329.                         printf("share type:\t");
  330.                         if(res[i].dwType = RESOURCETYPE_DISK)
  331.                                 printf("disk");
  332.                         else
  333.                                 printf("printer");
  334.                                 printf("\ncomment:\t%s\n", res[i].lpComment);
  335.                 }
  336.    }
  337.  
  338.    free(buf);
  339.    free(res);
  340.    return 0;
  341. }
  342.  
  343. /*
  344.  * close_session()
  345.  *    clean up our mess
  346.  */
  347. int close_session()
  348. {
  349.    DWORD                r;
  350.  
  351.    WSACleanup();
  352.    if(!OPT_NODEL)
  353.       r = WNetCancelConnection2(target, 0, TRUE);
  354.  
  355.    if(r != 0){
  356.       fprintf(stderr, "couldnt delete %s, returned %d\n", target, r);
  357.       return -1;
  358.    }
  359.    else{
  360.       if(VERB)
  361.                         printf("connection to %s deleted\n", target);
  362.    }
  363.  
  364.    return 0;
  365. }
  366.  
  367. /*
  368.  * handle_error()
  369.  *    util function to deal with some errors.
  370.  */
  371. void handle_error(DWORD err)
  372. {
  373.    switch(err){
  374.    case ERROR_ACCESS_DENIED:
  375.                 fprintf(stderr, "access is denied.\n");
  376.                 break;
  377.    case ERROR_BAD_NET_NAME:
  378.                 fprintf(stderr, "bad net name.\n");
  379.                 break;
  380.    case ERROR_EXTENDED_ERROR:
  381.                 fprintf(stderr, "an extended error occurred.\n");
  382.                 break;
  383.    case ERROR_INVALID_PASSWORD:
  384.                 fprintf(stderr, "invalid password.\n");
  385.                 break;
  386.    case ERROR_LOGON_FAILURE:
  387.                 fprintf(stderr, "bad username or password.\n");
  388.                 break;
  389.    case NO_ERROR:
  390.                 fprintf(stderr, "it worked\n");
  391.                 break;
  392.    case ERROR_BAD_NETPATH:
  393.                 fprintf(stderr, "network path not found.\n");
  394.                 break;
  395.    default:
  396.                 fprintf(stderr, "a random error occurred (%d).\n", err);
  397.         }
  398. }
  399.  
  400. /*
  401.  * prepend_str()
  402.  *    util funk to prepend chars to a string
  403.  */
  404. void prepend_str(char *orgstr, char *addthis)
  405. {
  406.    orgstr = _strrev(orgstr);
  407.    addthis = _strrev(addthis);
  408.    strcat(orgstr, addthis);
  409.    orgstr = _strrev(orgstr);
  410. }
  411. /*
  412.  * parse_cl()
  413.  *    try and make sense of the command line.  no, i dont have a win32 getopt.
  414.  *    yes, i know i should
  415.  */
  416. void parse_cl(int argc, char **argv)
  417. {
  418.    int     i, cc;
  419.    char    opt;
  420.    DWORD                r;
  421.  
  422.    OPT_SHARES = OPT_USERS = VERB = 0;
  423.  
  424.    for(i = 1; i < (argc); i++){
  425.       if( (*argv[i]) == '-'){
  426.                         opt = *(argv[i]+1);
  427.                         switch(opt){
  428.                         case 'a':
  429.                                 OPT_SHARES = 1;
  430.                                 OPT_USERS  = 1;
  431.                                 break;
  432.                         case 's':
  433.                                 OPT_SHARES = 1;
  434.                         break;
  435.                         case 'u':
  436.                                 OPT_USERS  = 1;
  437.                         break;
  438.                         case 'g':
  439.                                 OPT_GETUI  = 1;
  440.                                 if( (strlen(argv[i+1])) > USER_LEN)
  441.                                         bail("username too long (must be < 21)");
  442.                                 ZeroMemory(user, USER_LEN);
  443.                                 cc = strlen(argv[++i]);
  444.                                 r = MultiByteToWideChar(CP_ACP, 0, argv[i], cc, user, (cc + 2));
  445.                                 break;
  446.                         case 'd':
  447.                                 OPT_NODEL = 1;
  448.                                 break;
  449.                         case 'v':
  450.                                 VERB++;
  451.                                 break;
  452.                         default:
  453.                                 if( (opt != 'h') && (opt != '?') )
  454.                                         fprintf(stderr, "unknown option '%c'\n", opt);
  455.                                 usage(argv[0]);
  456.                                 break;
  457.                         }
  458.                 }
  459.    }
  460.  
  461.         if( (OPT_SHARES) && (VERB) )
  462.       printf("listing shares\n");
  463.    if( (OPT_USERS) && (VERB) )
  464.       printf("listing users\n");
  465.    if( (OPT_GETUI) && (VERB) )
  466.       wprintf(L"getting infos about user %s\n", user);
  467.    if(VERB)
  468.       printf("verbosity = %d\n", VERB);
  469. }
  470.  
  471. /*
  472.  * powerup()
  473.  *    just init stuff and parse the command line
  474.  */
  475. int powerup(int argc, char **argv)
  476. {
  477.    struct hostent       *hent;
  478.    u_long       addie;
  479.    WORD         werd;
  480.    WSADATA      data;
  481.    char         buf[256];
  482.    int          cc = 0, ucc = 0;
  483.  
  484.    if(argc < 3)
  485.       usage(argv[0]);
  486.  
  487.    parse_cl(argc, argv);
  488.    ZeroMemory(buf, 256);
  489.    strcpy(buf, argv[argc - 1]);
  490.  
  491. /* if not unc format get the ip */
  492.    if(buf[0] != '\\'){
  493.       if(VERB > 1)
  494.                         printf("target not in unc\n");
  495.  
  496.       werd = MAKEWORD(1, 1);
  497.       if( (WSAStartup(werd, &data)) !=0 )
  498.                         bail("couldnt init winsock\n");
  499.  
  500.       hent = (struct hostent *)malloc(sizeof(struct hostent));
  501.       if(hent == NULL)
  502.                         bail("malloc probs\n");
  503.  
  504.       if( (addie = inet_addr(buf)) == INADDR_NONE){
  505.                         hent = gethostbyname(buf);
  506.                         if(hent == NULL){
  507.                                 fprintf(stderr, "fatal: couldnt resolve %s.\n", buf);
  508.                                 return -1;
  509.                         }
  510.                         ZeroMemory(buf, 256);
  511.                         strcpy(buf, inet_ntoa(*(struct in_addr *)*hent->h_addr_list));
  512.       }
  513.       prepend_str(buf, "\\\\");
  514.    }
  515.    else
  516.       fprintf(stderr, "target already in unc\n");
  517.  
  518.    if( (strlen(buf) > (TARG_LEN - 1)) ){
  519.       free(buf);
  520.       bail("hostname too long (must be < 255 chars.)");
  521.       return -1;
  522.    }
  523.  
  524.    ZeroMemory(target, TARG_LEN);
  525.    strcpy(target, buf);
  526.  
  527.    ZeroMemory(utarg, TARG_LEN);
  528.    cc = strlen(target);
  529.    ucc = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, target, cc, utarg, cc);
  530.    if(ucc < 1){
  531.       bail("unicode conversion probs, sorry");
  532.       return -1;
  533.    }
  534.  
  535.    return 0;
  536. }
  537.  
  538. void usage(char *prog)
  539. {
  540.    fprintf(stderr, "usage: %s [asug<username>hv] <target>\n", prog);
  541.    fprintf(stderr, "\t-s:\t\tget share list\n");
  542.    fprintf(stderr, "\t-u:\t\tget user list\n");
  543.    fprintf(stderr, "\t-g: <username>\tget infos about just <username>\n");
  544.    fprintf(stderr, "\t-d:\t\tleave connection established on exit\n");
  545.    fprintf(stderr, "\t-a:\t\t-s + -u\n");
  546.    fprintf(stderr, "\t-h, -?:\t\tdisplay this help\n");
  547.    fprintf(stderr, "\t-v:\t\tbe verbose (use twice to be garrolous)\n");
  548.    exit(0);
  549. }
  550.  
  551. /*
  552.  * bail()
  553.  *    just whine and die
  554.  */
  555. void bail(const char *msg)
  556. {
  557.    fprintf(stderr, "fatal: %s\n", msg);
  558.    close_session();
  559.    exit(1);
  560. }
  561. <-->
  562.  
  563.  
  564. ----[  EOF
  565.  
  566.